import xml.etree.cElementTree as etree
from datetime import datetime
import urllib, urllib2
import logging, sys
import oauth

NS = 'http://www.w3.org/2005/Atom'

GU3API_URL = 'http://api.gu3.jp/v1/'
DEVELOPER_KEY = 'xxxxx'
DEVELOPER_SECRET = 'xxxxx'

class myHTTPErrorProcessor(urllib2.HTTPErrorProcessor):
    def http_response(self, request, response):
        code, msg, hdrs = response.code, response.msg, response.info()
        if code >= 300:
            response = self.parent.error(
                'http', request, response, code, msg, hdrs)
        return response

def oauth_request(method, url, data=None, headers={}):
    consumer = oauth.OAuthConsumer(DEVELOPER_KEY, DEVELOPER_SECRET)
    signature_method_hmac_sha1 = oauth.OAuthSignatureMethod_HMAC_SHA1()

    # access protected resources
    oauth_request = oauth.OAuthRequest.from_consumer_and_token(consumer, token=None, http_method=method, http_url=url, parameters=None)
    oauth_request.sign_request(signature_method_hmac_sha1, consumer, '')

    os_headers = oauth_request.to_header()
    if os_headers:
        headers.update(os_headers)
    try:
        opener = urllib2.build_opener(myHTTPErrorProcessor)
        urllib2.install_opener(opener)
        req = urllib2.Request(url, data, headers)
        response = urllib2.urlopen(req).read()
    except (urllib2.URLError, urllib2.HTTPError), e:
        logging.error(e.read())
        raise
    except:
        logging.error('%s %s' % sys.exc_info()[0:2])
        raise

    return response

def getPersonData(uid):
    """
    get Person Data
    >>> getPersonData(27)['profile_url']
    'http://gu3.jp/27/'
    """
    if not uid:
        return False
    url = GU3API_URL + 'people/%s/@self?format=xml' % uid
    try:
        xml = urllib2.urlopen(url).read()
        dom = etree.fromstring(xml)
        gd = dom.find(".//{%s}gender" % NS)

        dat = {
            'name'         : dom.findtext('.//{%s}name/*' % NS),
            'gender'       : {'key': gd.get('key'),
                              'displayvalues': dom.findtext('.//{%s}gender' % NS)},
            'profile_url'  : dom.findtext('.//{%s}profile_url' % NS),
            'thumbnail_url': dom.findtext('.//{%s}thumbnail_url' % NS),
            'photo_url'    : dom.findtext('.//{%s}photo_url' % NS),
            'area_code'    : dom.findtext('.//{%s}area_code' % NS),
            'updated'      : dom.findtext('.//{%s}updated' % NS),
            }
    except:
        logging.error('%s %s' % sys.exc_info()[0:2])
        dat = {}
    return dat

def getFriendData(uid):
    """
    get Friends
    >>> getFriendData(27)[0]['id']
    1
    """
    if not uid:
        return False
    url = GU3API_URL + 'people/%s/@friends?format=xml' % uid
    try:
        xml = urllib2.urlopen(url).read()
        dom = etree.fromstring(xml)

        entries = dom.findall('.//{%s}entry' % NS)
        dat = []
        for entry in entries:
            person = {'id'   : int(entry.findtext('{%s}id' % NS)),
                      'name' : entry.findtext('{%s}title' % NS),
                      }

            tn = entry.find("{%s}link" % NS)
            if tn != None and tn.get('rel') == 'thumbnail':
                person['thumbnail_url'] = tn.attrib['href']

            dat.append(person)

    except:
        logging.error('%s %s' % sys.exc_info()[0:2])
        dat = []
    return dat

def searchPerson(isfriend=None, user=None, age_min=None, age_max=None, gender=None, startIndex=None, itemsPerPage=None):
    """
    search Person
    >>> searchPerson(isfriend=1, user=27, gender='M', itemsPerPage=10)[0]['gender']['key']
    'MALE'
    """
    if not(isfriend or age_min or age_max or gender):
        return False

    params = {}
    if isfriend:
        params['isfriend'] = isfriend
        params['user'] = user
    if age_min:
        params['age_min'] = age_min
    if age_max:
        params['age_max'] = age_max
    if gender:
        params['gender'] = gender
    if itemsPerPage:
        params['itemsPerPage'] = itemsPerPage
    if startIndex:
        params['count'] = startIndex
    url_values = urllib.urlencode(params)
    url = GU3API_URL + 'people/search/?format=xml&' + url_values
    try:
        xml = oauth_request('GET', url)
        dom = etree.fromstring(xml)

        entries = dom.findall('.//{%s}entry' % NS)
        dat = []
        for entry in entries:
            gd = entry.find(".//{%s}gender" % NS)
            person = {'id'           : int(entry.findtext('{%s}id' % NS)),
                      'name'         : entry.findtext('{%s}title' % NS),
                      'profile_url'  : entry.findtext('.//{%s}profile_url' % NS),
                      'photo_url'    : entry.findtext('.//{%s}photo_url' % NS),
                      'gender'       :
                          {'key'          : gd.get('key'),
                           'displayvalues': entry.findtext('.//{%s}gender' % NS)},
                      'birthday'     : entry.findtext('.//{%s}birthday' % NS),
                      'lastlogin'    : entry.findtext('.//{%s}lastlogin' % NS),
                      }

            tn = entry.find("{%s}link" % NS)
            if tn != None and tn.get('rel') == 'thumbnail':
                person['thumbnail_url'] = tn.attrib['href']

            dat.append(person)
    except:
        logging.error('%s %s' % sys.exc_info()[0:2])
        dat = {}
    return dat

def postActivity(uid, message):
    """
    Post Activity
    >>> postActivity(27, 'test')
    ''
    """
    if not uid or not message:
        return False

    body = '''<?xml version="1.0" encoding="UTF-8"?>
    <entry xmlns="http://www.w3.org/2005/Atom"
           xmlns:osapi="http://opensocial.org/2008/opensocialapi">
    <title><![CDATA[%s]]></title>
    </entry>
    ''' % message.encode('utf-8')

    headers = {'Content-Type': 'application/atom+xml; charset=utf-8',
               'Content-Length': str(len(body)),
               }

    try:
        xml = oauth_request('POST', GU3API_URL + 'activity/%s/' % uid,
                            body, headers)
        return xml
    except:
        return False

def message(title, body, toIds, at=None):
    """
    send miniMail
    >>> message('title', 'body', '1,27', 1222437669)
    ''
    """
    if not title or not body or not toIds:
        return False

    if toIds == '__ALL__':
        tos = [toIds,]
    else:
        tos = str(toIds).split(',')
    recipient = ''
    for to in tos:
        recipient += '<osapi:recipient>%s</osapi:recipient>' % to

    updated = ''
    if at:
        updated = '<updated>%sZ</updated>' % datetime.fromtimestamp(at).isoformat()

    body = '''<?xml version="1.0" encoding="UTF-8"?>
    <entry xmlns="http://www.w3.org/2005/Atom"
           xmlns:osapi="http://opensocial.org/2008/opensocialapi">
    %s
    %s
    <title><![CDATA[%s]]></title>
    <content><![CDATA[%s]]></content>
    </entry>
    ''' % (recipient, updated, title, body)

    headers = {'Content-Type': 'application/atom+xml; charset=utf-8',
               'Content-Length': str(len(body)),
               }

    try:
        xml = oauth_request('POST', GU3API_URL + 'messages/outbox',
                            body, headers)
        return xml
    except:
        return False

def testAuth():
    """
    Test method for OAuth
    >>> testAuth()['TestResponse']['message']
    'OK'
    """
    try:
        xml = oauth_request('GET', GU3API_URL + 'test/auth')
        xml = eval(xml)
    except:
        return False
    return xml

def _test():
    import doctest
    doctest.testmod()

if __name__ == '__main__':
    _test()
